/**
 * Klasa opisujaca pojedynczy krok planu uzyskanu z algorytmu Step
 */
package stripsLanguage;

import java.util.ArrayList;
import java.util.List;

import exceptions.NoPredicateFoundException;

public class Step extends Operator {

	// jak id 0, to znaczy, ze brak przypisan
	List<Instance> Instances;

	/** identifier of the operator **/
	private int Id;
	
	public Step(
		int id,
		int typeOfOperator,
		String name,
		List <Predicate> preconditions,
		List <Predicate> effects)
	{
		super(typeOfOperator, name, preconditions, effects);
		Id = id;
		Instances = new ArrayList<Instance>();
	}
	
	/**
	 * creates an exact copy of this Step
	 * @return
	 */
	public Step copyStep(List<Operator> operators)
	{
		if(Id == 1 || Id == 2) return this;
		for(Operator operator: operators)
			if(operator.getTypeOfOperator() == this.getTypeOfOperator())
			{
				Step step = new Step(
					Id, // id
					TypeOfOperator,
					Name,
					operator.copyPreconditions(),
					operator.copyEffects());
				step.unifyInstances();
				for(int p = 0; p < Preconditions.size(); p++)
					step.getPreconditions().get(p).setIdOfPredicate(Preconditions.get(p).getIdOfPredicate());					
				for(int p = 0; p < Effects.size(); p++)
					step.getEffects().get(p).setIdOfPredicate(Effects.get(p).getIdOfPredicate());
				// nadaje instancjom wartosci
				for(int i = 1; i <= Instances.size(); i++)
					step.setInstance(
						i, new Instance(Instances.get(i-1).getName(),Instances.get(i-1).getId()));
				return step;
			}
		return null;
	}

	public int getId() {
		return Id;
	}

	public Instance getInstance(int localId)
	{	
		return Instances.get(localId-1);
	}

	public List<Instance> getInstances()
	{	
		return Instances;
	}
	
	public int getGlobalId(int localId)
	{
		return Instances.get(localId-1).getId();
	}
	
	public Predicate getPredicateById(int id) throws NoPredicateFoundException
	{
		for(Predicate p: Preconditions)
			if(p.getIdOfPredicate() == id)
				return p;
		for(Predicate p: Effects)
			if(p.getIdOfPredicate() == id)
				return p;
		throw new NoPredicateFoundException();
	}
	
	public void setInstance(int localId, Instance instance)
	{
		Instances.get(Math.abs(localId)-1).setId(instance.getId());
		Instances.get(Math.abs(localId)-1).setName(instance.getName());
	}	
	
	public String toString()
	{
		String newline = System.getProperty("line.separator");
		String s = newline + "\t\t(" + Id + ", " + getName() + ")";
		s += newline + "\t\t\tPreconditions: ";
		if(Preconditions != null)
			for (Predicate p: Preconditions)
				try {
					s += p.toString(false);
				} catch (Exception e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}			
		s += newline + "\t\t\tEffects: ";
		if(Effects != null)
			for (Predicate p: Effects)
				try {
					s += p.toString(true);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		s += newline + "\t\t\tInstances: ";
		for(int i = 1; i <= Instances.size(); i++)
			s += "(" + i + ": "	+ Instances.get(i-1).getId() + "," 
				+ Instances.get(i-1).getName() + ")";
		return s;
	}
	
	public void unifyInstances()
	{
		
		// count nr of different instances
		int ctr = 1;
		boolean found = true;
		// najpierw trzeba znalezc wszystkie id instancji i reprezentantow tych id
		while(found)
		{
			found = false;
			for(Predicate p: Effects)
				for(Instance i: p.getArguments())
					if(i.getId() == ctr)
					{						
						++ctr;
						found = true;					
					}
			for(Predicate p: Preconditions)
				for(Instance i: p.getArguments())
					if(i.getId() == ctr)
					{
						++ctr;
						found = true;						
					}
		}
		
		for(int i = 1; i < ctr; i++)
			Instances.add(
				new Instance(null, -i));
		
		// teraz trzeba przepisac te wskazniki
		for(Predicate p: Effects)
			for(int i = 0; i < p.getArguments().size(); i++)
			{	
				p.setInstance(i, (Instances.get(
					p.getArguments().get(i).getId()-1)));
			}
		for(Predicate p: Preconditions)
			for(int i = 0; i < p.getArguments().size(); i++)
				p.setInstance(i, Instances.get(
					p.getArguments().get(i).getId()-1));	
	}
}
